import path from 'path';
import fs from 'fs';
import Api from '../request/api.js';
import { sleep, log, md5 } from '../utils/utils.js';
import process from 'process';
import dotenv from 'dotenv';
import puppeteer from 'puppeteer-extra';
import axios from 'axios';
import { PayType, TicketChannel } from '../constant/index.js';

const ua =
  'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36 MicroMessenger/6.8.0(0x16080000) NetType/WIFI MiniProgramEnv/Mac MacWechat/WMPF XWEB/30817';

// const waitSelectTime = 300000; // 选座等待时间
dotenv.config();
const {
  EXECUTABLE_PATH,
  CINEMA_ACC_ID,
  CINEMA_TOKEN = '',
  CINEMA_ACCOUNT,
  CINEMA_CITYCODE,
  CINEMA_PWD,
  CINEMA_LINKID,
  CINEMA_CODE,
} = process.env;

const API = new Api();

export default class Xingyun {
  // token
  loginToken = CINEMA_TOKEN || '';

  // 用户信息
  ticketUser = {};

  // 会员卡信息
  memberCardInfo = null;

  // 座位
  selectSeatList = '';

  // 接口请求头
  requestHeader = {
    'User-Agent': ua,
    Accept: 'application/json',
    'Accept-Language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
    'Content-Type': 'application/x-www-form-urlencoded',
    'gray-lease-code': 'GS',
    'Sec-Fetch-Dest': 'empty',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Site': 'same-site',
    Pragma: 'no-cache',
    'Cache-Control': 'no-cache',
  };

  // 订单信息
  order = {
    state: '',
    ticketCode: '',
    paramDetail: {}, // 订单详情参数
  };

  // 锁定订单ID
  lockOrderId = '';

  // 创建订单ID
  orderConfirmId = '';

  // data
  dataJson = null;

  // cinemasCode
  cinemasCode = '';

  // 影院ID
  ccode = 31129701;

  // 小程序版本
  ver = '20231121';

  // 设置版本和Ccode
  setVer(ver) {
    this.ver = ver;
  }

  // 设置影院和TOKEN
  setCinemaIdAndToken(ccode, cinemasCode, loginToken = '') {
    this.ccode = ccode;
    this.loginToken = loginToken;
    this.cinemasCode = cinemasCode;
  }

  // 写入本地保存
  setOrderState(state, ticketCode = '', paramDetail = {}) {
    if (ticketCode) {
      this.order.ticketCode = ticketCode;
    }
    this.order.paramDetail = { ...this.order.paramDetail, ...paramDetail };
    this.order.state = state;

    fs.writeFileSync(
      './orderJson/' + this.dataJson.sn + '.json',
      JSON.stringify(this.order, null, 2),
      {
        flag: 'w',
      },
      (err) => {
        if (err) {
          console.error('订单状态写入', err);
        }
      }
    );
  }

  // 订单开始 初始化
  async orderStart(dataJson) {
    this.order = {
      state: '',
      ticketCode: '',
      paramDetail: {},
    };
    this.dataJson = dataJson;
    this.selectSeatList = null;
    this.memberCardInfo = null;
    this.orderConfirmId = '';
    this.lockOrderId = '';
  }

  // 获取座位信息
  async getSeat() {
    const dataJson = this.dataJson;
    // 选座
    const { scheduleKey } = dataJson.showObj;
    const seats = await this.requestPageApi('api/wechat/movie/getSessionSeat', {
      cinema_code: this.ccode,
      session_code: scheduleKey,
    });
    if (!seats || seats.length === 0) {
      log('场次数据获取失败 ' + JSON.stringify(seats), 'error');
      throw new Error('场次选择失败');
    }

    // 订单座位
    // 座位转成 [[11,2],[11,3]]
    const seatListArr = this.dataJson.seatList.map((i) =>
      i
        .match(/[\d|A-Za-z]+/g)
        .map((d) => (isNaN(Number(d)) ? d.toLocaleUpperCase() : Number(d)))
    );
    const seatList = [];
    // seat {"seat_type":"normal","bind_id":"0","seat_zone_code":"3112970100000001","seat_row":"3","seat_id":"3112970100004823","seat_col":"12","graph_row":3,"seat_code":"83b6793b60a52414","tips":"3排12座","seat_state":"normal","graph_col":12}
    for (const seat of seats) {
      if (
        !seatListArr.find(
          (st) => st[0] == seat.seat_row && st[1] == seat.seat_col
        )
      ) {
        continue;
      }

      if (seat.seat_state !== 'normal') {
        throw new Error(
          `座位已被锁定 ${this.dataJson.from} ${this.dataJson.cinemaName}`
        );
      }

      seatList.push({
        sectionNo: seat.seat_zone_code,
        seatId: seat.seat_id,
        seatName: seat.tips,
        row: seat.seat_row,
        col: seat.seat_col,
      });
    }
    if (seatList.length < dataJson.seatList.length) {
      throw new Error('座位未找到');
    }

    this.selectSeatList = seatList;
    return seatList;
  }

  // 锁定座位
  /**
   * [{"areaId":"0","column":3,"columnName":"2","flag":0,"name":"1排2座","row":1,"rowName":"1","seatId":"000000031026-1-3","status":1}]
   */
  async lockSeat() {
    const dataJson = this.dataJson;
    const { showNo } = dataJson.showObj;
    // 座位锁定请求
    const lockBizData = await this.requestPageApi(
      'api/wechat/ticket/order/lock',
      {
        cinema_code: this.ccode,
        session_id: showNo,
        seat_ids: this.selectSeatList.map((s) => s.seatId),
      }
    );
    if (lockBizData && lockBizData.net_order) {
      // 成功锁座
      log('座位锁定成功');
      this.lockOrderId = lockBizData.net_order;
    } else {
      // 锁座失败
      log('座位锁定请求失败 ' + JSON.stringify(lockBizData), 'error');
      throw new Error('锁座失败[RETRY]:' + (lockBizData.msg || ''));
    }
  }

  // 提交订单信息
  async submitOrderInfo(cinemaInfo) {
    const selectSeatList = this.selectSeatList;
    // 支付方式
    let payType;
    let costFee = 999999;
    if (cinemaInfo.settle_type == PayType.COUPON) {
      ({ payType, costFee } = this.getCouponCost(cinemaInfo));
    } else {
      throw new Error('支付方式未支持');
    }

    // 更新成本
    log('更新成本 ' + JSON.stringify({ costFee, payType }));
    await API.updateOrderCost(this.dataJson.id, costFee || 999999);
    const sellAmount = Number(this.dataJson.sellAmount);
    // force_ticket是否强制出票
    if (sellAmount > 0 && sellAmount <= costFee && !cinemaInfo.force_ticket) {
      throw new Error(
        `成本高于报价[类型${payType}-成本${costFee}-报价${sellAmount}]`
      );
    }
    // 开始进行支付
    let payResult = false;
    if (payType === PayType.COUPON) {
      // 使用线下券
      payResult = await this.useCoupon();
    }
    if (!payResult) {
      throw new Error('支付失败-' + payType);
    }
    // 设置订单状态
    this.setOrderState('success', '', {
      costFee,
      payType,
      orderId: this.orderConfirmId,
    });

    // 从订单列表里获取订单信息
    return this.getOrderInfo();
  }

  // 线下券成本
  getCouponCost(cinemaInfo) {
    // 线下券
    const ticketCount = this.dataJson.seatList.length;
    const { isSpec, weight, couponPlus = 0 } = this.dataJson.showObj;
    return {
      payType: PayType.COUPON,
      costFee: isSpec
        ? cinemaInfo.coupon_fee * weight * ticketCount + couponPlus
        : cinemaInfo.coupon_fee * ticketCount,
    };
  }

  // 使用线下券
  async useCoupon() {
    const selectSeatList = this.selectSeatList;
    const { showNo } = this.dataJson.showObj;
    // 获取线下券列表
    const couponListData = await this.requestPageApi(
      'api/wechat/api/ticket/order/couponPrice',
      {
        cinema_code: this.ccode,
        sessionId: showNo,
        seatIds: this.selectSeatList.map((s) => s.seatId),
        net_order: this.lockOrderId,
        couponIds: [],
      }
    );
    if (!couponListData || !couponListData.coupon_list) {
      throw new Error('线下券数据获取失败[RETRY]');
    }

    // 更新券数
    let useCouponNum = this.dataJson.seatList.length;
    const { isSpec, weight } = this.dataJson.showObj;
    if (isSpec) {
      // 特殊影厅
      useCouponNum = useCouponNum * weight;
    }
    const totalNeedCouponNum = useCouponNum;
    if (couponListData.coupon_list.length < useCouponNum) {
      throw new Error(
        `线下券数量不足[${couponListData.coupon_list.length}-${useCouponNum}]`
      );
    }
    // 查找使用优惠券
    const ticketInfos = [];
    for (const couponInfo of couponListData.coupon_list) {
      if (useCouponNum <= 0) {
        break;
      }
      if (!couponInfo.enabled || couponInfo.selected) {
        continue;
      }
      ticketInfos.push(couponInfo);
      useCouponNum = useCouponNum - 1;
    }
    if (ticketInfos.length < totalNeedCouponNum) {
      throw new Error(
        `线下券可用的券数不足[${ticketInfos.length}-${totalNeedCouponNum}]`
      );
    }

    // 验证优惠券
    const quanCodes = ticketInfos.map((t) => t.id);
    const validatorData = await this.requestPageApi(
      'api/wechat/api/ticket/order/couponPrice',
      {
        cinema_code: this.ccode,
        sessionId: showNo,
        seatIds: this.selectSeatList.map((s) => s.seatId),
        net_order: this.lockOrderId,
        couponIds: quanCodes,
      }
    );
    if (!validatorData || !validatorData.total) {
      log('线下券验证失败 ' + JSON.stringify(validatorData));
      throw new Error('验券失败[TRY]:' + validatorData.msg);
    }
    if (validatorData.bill > 0) {
      throw new Error('线下券需要额外支付金额:' + validatorData.bill);
    }

    // 创建订单
    const orderInfo = await this.requestPageApi(
      'api/wechat/ticket/order/prePay',
      {
        cinema_code: this.ccode,
        net_order: this.lockOrderId,
        bill: 0,
        useActivity: 0,
        couponIds: quanCodes,
        seats: this.selectSeatList.map((s) => s.seatId),
        tel: CINEMA_ACCOUNT,
      }
    );
    if (!orderInfo || !orderInfo.order_no) {
      log('线下券使用失败 ' + JSON.stringify(orderInfo));
      throw new Error('线下券兑换失败[TRY] ' + orderInfo.msg);
    }
    if (Number(orderInfo.order_price) > 0) {
      log('线下券使用失败 ' + JSON.stringify(orderInfo));
      throw new Error(
        '线下券兑换失败[TRY] 需额外支付:' + orderInfo.order_price
      );
    }

    // 确认支付
    const payInfo = await this.requestPageApi(
      'api/wechat/ticket/order/payByWechat',
      {
        cinema_code: this.ccode,
        net_order: this.lockOrderId,
        operateType: 'click',
      }
    );
    if (!payInfo || !payInfo.order_no) {
      log('线下券兑换失败 ' + JSON.stringify(orderInfo));
      throw new Error('线下券兑换失败 ' + orderInfo.msg);
    }

    // 更新券列表
    await API.uploadCoupon(
      couponListData.coupon_list
        .filter((i) => !quanCodes.includes(i.id))
        .map((coupon) => ({
          type: 1,
          couponNo: coupon.id,
          status: coupon.enabled,
          timeStart: new Date(coupon.start_time).getTime() / 1000,
          timeEnd: new Date(coupon.end_time + ' 23:59:59').getTime() / 1000,
          couponVer: md5(coupon.setting_id || 'x'),
          couponName: coupon.name || '',
          couponInfo: `${coupon.flow_customer} ${coupon.range}` || '',
        })),
      CINEMA_ACC_ID,
      CINEMA_ACCOUNT,
      TicketChannel.XINGYUN
    );

    await API.updateCouponNum(couponListData.coupon_list.length - useCouponNum);

    this.orderConfirmId = payInfo.order_no;
    return true;
  }

  // 获取订单信息
  async getOrderInfo() {
    const filePath = './orderJson/' + this.dataJson.sn + '.json';
    if (!fs.existsSync(filePath)) {
      return false;
    }
    const buffer = fs.readFileSync(filePath);
    const fileContent = buffer.toString();
    if (!fileContent) {
      return false;
    }
    const orderState = JSON.parse(fileContent);
    this.order = orderState;

    const orderDetailData = await this.requestPageApi(
      'api/wechat/ticket/order/detail',
      {
        cinema_code: this.ccode,
        order_no: orderState.paramDetail.orderId,
      }
    );
    if (!orderDetailData || !orderDetailData.order_no) {
      log(
        '获取订单详情失败 ' +
          JSON.stringify(orderState) +
          ' ' +
          JSON.stringify(orderDetailData)
      );
      throw new Error('获取订单详情失败[RETRY] ' + (orderDetailData.msg || ''));
    }
    let uploadLink = '';
    if (this.dataJson.screenshot) {
      const startDatetime =
        orderDetailData.movie_info.session_datetime.split(' ');
      // 上传截图
      uploadLink = await this.screenshotAndUpload({
        mobile: orderDetailData.mobile,
        order_num: orderDetailData.ticket_num,
        movie_name: orderDetailData.movie_info.movie_name,
        movie_img_url: orderDetailData.movie_info.poster_url,
        cinema_name: orderDetailData.cinema_alias,
        hall_name: orderDetailData.movie_info.hall_name,
        seat_info: orderDetailData.movie_info.seats,
        start_date: startDatetime[0],
        start_time: startDatetime[1],
        create_time: orderDetailData.create_time,
        movie_format: orderDetailData.movie_info.hall_type,
        msg: '',
        total_price: orderDetailData.price_detail.replace('￥'),
        serial_number_1: orderDetailData.order_no,
        serial_number_2: '',
        qrcode: orderDetailData.order_no,
        ticket_code_type: 0,
        seats: orderDetailData.movie_info.seats,
        message: orderDetailData.cinema_alias,
        tel: '',
      });
    }
    let ticketCode = orderDetailData.order_no;
    this.setOrderState('success', ticketCode);

    return {
      orderId: orderDetailData.order_no,
      payType: orderState.paramDetail.payType,
      ticketCode,
      uploadLink,
    };
  }

  // 截图上传
  async screenshotAndUpload(detail) {
    const sep = path.sep;
    const data = {
      mobile: detail.mobile,
      order_num: detail.order_num,
      movie_name: detail.movie_name,
      movie_img_url: detail.movie_img_url.replace('/', '/'),
      cinema_name: detail.cinema_name,
      hall_name: detail.hall_name,
      seat_info: detail.seat_info,
      start_date: detail.start_date,
      start_time: detail.start_time,
      create_time: detail.create_time,
      movie_format: detail.movie_format,
      msg: detail.msg,
      total_price: detail.total_price,
      serial_number_1:
        detail.ticket_code_type === '0'
          ? detail.qrcode
          : detail.serial_number_1,
      serial_number_2: detail.serial_number_2,
      qrcode: detail.qrcode,
      ticket_code_type: detail.ticket_code_type,
      seats: detail.seats,
      message: detail.message,
      tel: detail.tel,
    };
    // 本地路径
    const url = `file://${path.resolve(
      './'
    )}${sep}html${sep}order-detail.html?data=${encodeURIComponent(
      JSON.stringify(data)
    )}`;
    // 初始化
    const browser = await puppeteer.launch({
      executablePath: EXECUTABLE_PATH,
      //设置超时时间
      timeout: 15000,
      ignoreHTTPSErrors: true,
      headless: true,
      args: ['--disable-dev-shm-usage', '--no-sandbox', '--disable-plugins'],
    });
    const page = await browser.newPage();
    await page.goto(url);
    await page.setViewport({
      width: 375,
      height: 590,
    });

    // 截图
    const screenshotPath = './screenshot/' + this.dataJson.sn + '.png';
    await page.screenshot({
      path: screenshotPath,
    });
    await browser.close();

    // 上传截图
    return await API.uploadScreenshot(screenshotPath);
  }

  // 订单取消
  async cancelOrder() {
    if (this.orderConfirmId) {
      // 解锁请求
      return await this.requestPageApi('api/wechat/ticket/order/refund"', {
        net_order: this.orderConfirmId,
        cinema_code: this.ccode,
      });
    }
    return true;
  }

  // 解锁座位
  async unlockSeat() {
    if (this.lockOrderId) {
      // 解锁请求
      return await this.requestPageApi('api/wechat/ticket/order/unlock', {
        cinema_code: this.ccode,
        net_order: this.lockOrderId,
      });
    }
    return true;
  }

  // 页面接口请求
  async requestPageApi(path, data = {}, method = 'POST') {
    let url = `https://${this.cinemasCode}.xingyun.1905.com/${path}`;
    // 设置影院ID;
    let requestBody = {
      ...data,
    };
    const res = await axios
      .request({
        url,
        method,
        data: requestBody,
        timeout: 15000,
        headers: {
          Host: `${this.cinemasCode}.xingyun.1905.com`,
          referer:
            'https://servicewechat.com/wx6d71ab6c091252c5/6/page-frame.html',
          xweb_xhr: '1',
          accept: '*/*',
          'sec-fetch-mode': 'cors',
          'sec-fetch-dest': 'empty',
          'accept-language': 'zh-CN,zh',
          'Sec-Fetch-Site': 'same-site',
          'User-Agent': ua,
          timestamp: `${Date.now()}`,
          'content-type': 'application/json',
          ccode: this.ccode,
          ver: this.ver,
          token: this.loginToken,
        },
      })
      .catch((e) => {
        log(
          `Xingyun请求接口[${url}]异常 ${JSON.stringify(
            requestBody
          )} ${JSON.stringify(e)}`,
          'error'
        );
        return {
          status: -2, // 超时
          data: {
            status: -101,
            msg: e.message,
          },
        };
      });

    if (!res.data || res.data.status !== 0) {
      log(
        `Xingyun请求接口[${url}]出错-${res.status} ${JSON.stringify(
          requestBody
        )} ${JSON.stringify(res.data)}`,
        'error'
      );
      if (res.data && res.data.status === '205') {
        // 登录态失效
        this.ticketUser.cinemaAccId &&
          (await API.authExpire(this.ticketUser.cinemaAccId));
        throw new Error('账号登录失效');
      }
      return res.data;
    }

    return res.data.data;
  }

  // 订单回退
  async orderRollback(dataJson) {
    log('回调订单状态,出票失败');
    // 订单锁定取消
    await API.orderRollback(dataJson.id, dataJson.msg).catch((e) =>
      console.error('取消订单请求异常', e)
    );
    if (this.lockOrderId) {
      // 仅仅是座位锁定成功 订单取消锁定
      const unlockRes = await this.unlockSeat();
      log(`解锁座位:${this.lockOrderId} ${JSON.stringify(unlockRes)}`);
    }

    return true;
  }

  // 更新账户场次信息
  async updateShow(taskData) {
    this.setCinemaIdAndToken(
      taskData.cinema_data.linkid,
      taskData.cinemas_code,
      taskData.login_token
    );

    // 获取影片列表
    const films = await this.requestPageApi(
      'api/wechat/movie/list/by_session_new',
      {
        cinema_code: this.ccode,
      }
    );
    // 影片为空
    if (!films || !films.movie_info || films.movie_info.length === 0) {
      await sleep(2000);
      return;
    }

    const filmMap = {};
    for (const film of films.movie_info) {
      const filmName = film.movie_name;
      filmMap[filmName] = [];
      // 查找单个影片的场次信息
      const showsData = await this.requestPageApi(
        'api/wechat/movie/getSessionList',
        {
          cinema_code: this.ccode,
          movie_exclude_version: film.movie_exclude_version || film.movie_code,
        }
      );
      const showList = showsData.session_map;
      for (const showDay in showList) {
        for (const schedule of showList[showDay]) {
          const showTime = `${showDay} ${schedule.start_time}:00`;
          filmMap[filmName].push({
            showTime,
            isSpec: ['IMAX', '4D', 'VIP'].some((w) =>
              schedule.hall_alias.includes(w)
            ),
            hallId: schedule.hall_code,
            scheduleKey: schedule.session_code,
            showNo: schedule.session_id,
            hallName: schedule.hall_alias,
            displayPrice:
              schedule.mem_price > 0
                ? Math.round(
                    schedule.mem_price * taskData['vip_cost_ratio'] * 100
                  )
                : schedule.price * 100, // 会员卡价格*系数
            price: schedule.price * 100, // 标准价格
            standardPrice: schedule.price * 100, // 展示原价
            lowestPrice: schedule.mem_price * 100, // 发行价
            ticketFee: 0, // 影院手续费
          });
        }
      }
    }

    await API.updateShowlist(
      taskData.cinema_id,
      taskData.account_id,
      taskData.vip_price_status,
      filmMap
    );

    log(
      `${taskData['cinema_name']}[${taskData['cinemas_code']}] 场次数据更新成功[${taskData.account}]`
    );
  }

  // 更新院线
  async updateCinemas(taskData) {
    const { config, cinemas_code } = taskData;
    this.setVer(config.ver);
    this.setCinemaIdAndToken(config.ccode, cinemas_code);

    const cinemas = await this.requestPageApi(
      'api/wechat/global/getCinemaList',
      {}
    );
    if (!cinemas || !Array.isArray(cinemas.cinemaList)) {
      return;
    }

    const cityCinemasMap = [];
    cinemas.cinemaList.forEach((ele) => {
      cityCinemasMap.push({
        address: ele.addr || '',
        cityName: ele.city || '',
        cinemaName: ele.alias,
        cinemaLinkId: ele.code,
      });
    });

    await API.updateCinemasData(
      taskData.id,
      taskData.vip_price_status,
      cityCinemasMap
    );

    log(
      `${taskData['cinemas_name']}[${taskData['cinemas_code']}] 院线数据更新成功`
    );
  }
}
